#include "IotGatway.h"

#include <net/if.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>

#include "StringUtility.h"
#include "UdpCommunicator.h"
#include "NetworkManager.h"
#include "INetwork.h"


IotGatway::IotGatway() {
    //ctor
}

IotGatway::~IotGatway() {
    delete mpcommunicator;
    mpcommunicator = nullptr;
}



bool IotGatway::configureAndConnect(const VerbInfo& verbInfo){
    UdpCommunicator* pcommunicator = new UdpCommunicator();
    pcommunicator->allocHandle();
    timeval tv{verbInfo.timeout / 1000, (verbInfo.timeout % 1000) * 1000};

    mpcommunicator = pcommunicator;

    pcommunicator->setTimeout(tv);
    return pcommunicator->connect(verbInfo);
}



bool IotGatway::doVerb(const VerbInfo& verbInfo, VerbResult& verbResult) {
    NetworkManager& networkManager = NetworkManagerSingleton::instance();
    configureAndConnect(verbInfo);

    if (&networkManager.methernet != networkManager.mpactiveNetwork){
        INetwork* ptempNetwork = &networkManager.methernet;
        short flags = ptempNetwork->getIterfaceFlags(ptempNetwork->mname, ptempNetwork->msocketFd);
        flags |= IFF_UP | IFF_RUNNING;
        ptempNetwork->setIterfaceFlags(ptempNetwork->mname, ptempNetwork->msocketFd, flags);

        sockaddr_in addr, mask;
        addr.sin_family = AF_INET;
        inet_pton(AF_INET, "192.168.254.253", &addr.sin_addr);
        mask.sin_family = AF_INET;
        inet_pton(AF_INET, "255.255.255.252", &mask.sin_addr);

        ptempNetwork->setIterfaceAddressParameter(ptempNetwork->mname, ptempNetwork->msocketFd, SIOCSIFADDR, addr);
        ptempNetwork->setIterfaceAddressParameter(ptempNetwork->mname, ptempNetwork->msocketFd, SIOCSIFNETMASK, mask);

    }
    mpcommunicator->bindToInterface(networkManager.methernet);

    std::string data;
    std::string const *pData = &verbInfo.data;
    if (verbInfo.dataIsBinary){
        StringUtility::stringToBinary(verbInfo.data, data);
        pData = &data;
    }

    ssize_t returnCode = mpcommunicator->send(*pData);
    if (0 <= returnCode && verbInfo.haveResponse){
        std::string resultString;
        returnCode = mpcommunicator->recv(resultString);
        if (0 <= returnCode){
            if (verbInfo.responseIsBinary){
                StringUtility::dumpMemory(reinterpret_cast <const uint8_t*>(resultString.data()), resultString.size(), "%02x", verbResult.result);
            } else {
                verbResult.result = resultString;
            }
        }
    }

    if (0 > returnCode) {
        BUILD_EXCEPTION_ERROR(FirmwareError::IOTGATWAY_COMMAND_ERROR, returnCode, errno, "forward data by udp failed");
    }

    return true;
}



